package location

import (
	"fmt"
	"io"
	"os"
	"path"
	"path/filepath"

	"device-admin/config"
	"device-admin/config/mysql"
	"device-admin/internal/models"
	"device-admin/internal/pkg/file"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"github.com/samber/lo"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"
)

type Brand struct{}

// Brand 判断楼层是否存在
func (Brand) BrandExists(brandID string) (models.Brand, error) {
	db := mysql.NewDB()
	// 判断楼层是否存在
	var brand models.Brand
	rowsAffected := db.Model(&models.Brand{}).
		Where("id = ?", brandID).
		Take(&brand).RowsAffected
	if rowsAffected <= 0 {
		return models.Brand{}, errorx.New("品牌不能存在", -1)
	}
	return brand, nil
}

// Detail 详情
func (Brand) Detail(id string) (models.Brand, error) {
	db := mysql.NewDB()
	var brand models.Brand
	rowsAffected := db.Model(&models.Brand{}).Where("id = ?", id).Take(&brand).RowsAffected
	if rowsAffected <= 0 {
		return models.Brand{}, errorx.New("品牌不存在", -1)
	}
	return brand, nil
}

type BrandList struct {
	ID           string `json:"id" gorm:"column:id"`
	Logo         string `json:"logo" gorm:"column:logo"`                   // 品牌logo
	Name         string `json:"name" gorm:"column:name"`                   // 品牌名称
	Desc         string `json:"desc" gorm:"column:desc"`                   // 品牌描述
	FloorID      string `json:"floor_id" gorm:"column:floor_id"`           // 楼层id
	FloorName    string `json:"floor_name" gorm:"column:floor_name"`       // 楼层名称
	ShopNo       string `json:"shop_no" gorm:"column:shop_no"`             // 品牌铺号
	ContactPhone string `json:"contact_phone" gorm:"column:contact_phone"` // 联系电话
	PositionName string `json:"position_name" gorm:"column:position_name"` // 位置点名称
}

// List 品牌列表
func (Brand) List(page, limit int, name, locationID string) (list []BrandList, total int64, err error) {
	db := mysql.NewDB()
	tx := db.Model(models.Brand{})
	tx = tx.Joins("LEFT JOIN floor_brand ON floor_brand.brand_id = brand.id").
		Joins("LEFT JOIN floor ON floor.id = floor_brand.floor_id").
		Joins("LEFT JOIN floor_position ON floor_position.id = floor_brand.position_id")

	// 私有品牌
	tx = tx.Where("brand.location_id = ?", locationID)

	if name != "" {
		tx = tx.Where("brand.name LIKE ?", "%"+name+"%")
	}
	tx = tx.Group("brand.name").Session(&gorm.Session{})
	tx.Count(&total)

	tx = tx.Select(
		"brand.id",
		"brand.logo",
		"brand.name as name",
		"brand.desc",
		"floor.id as floor_id",
		"floor.name as floor_name",
		"floor_brand.shop_no",
		"floor_brand.contact_phone",
		"floor_position.name as position_name",
	)
	helper.Gorm{}.Paginate(tx, page, limit).Find(&list)
	return list, total, nil
}

// AddBrand 新增品牌
func (Brand) AddBrand(name, logo, desc, locationID, floorID, contactPhone, shopNO string) (string, error) {
	db := mysql.NewDB()

	// 判断品牌名称是否已经存在
	var count int64
	db.Model(&models.Brand{}).Where("name = ?", name).Count(&count)
	if count > 0 {
		return "", errorx.New("品牌名称已存在", -1)
	}
	// 新增logo
	var brand models.Brand
	// 判断导航地图文件是否存在
	if _, err := os.Stat(logo); err == nil {
		// 从临时文件夹中移动地图导航文件
		saveDir := path.Join(config.Config.FileSaveDir, "brand")
		logo, err := file.SaveUploadFileTo(logo, saveDir)
		if err != nil {
			return "", err
		}
		brand.Logo = logo
	}
	brand.Name = name
	brand.Desc = desc
	brand.LocationID = locationID
	rowsAffected := db.Model(&models.Brand{}).Create(&brand).RowsAffected
	if rowsAffected <= 0 {
		return "", errorx.New("新增品牌失败", -1)
	}

	// 创建或更新关联
	if floorID != "" {
		var count int64
		db.Model(&models.Floor{}).Where("id = ?", floorID).Count(&count)
		if count <= 0 {
			return "", errorx.New("楼层不存在", -1)
		}
		db.Where(models.FloorBrand{
			BrandID: brand.ID,
		}).Assign(models.FloorBrand{
			FloorID:      floorID,
			ContactPhone: contactPhone,
			ShopNO:       shopNO,
		}).FirstOrCreate(&models.FloorBrand{})
	}

	return brand.ID, nil
}

// DownloadBrandTemplate 下载品牌导入模版
func (Brand) DownloadBrandTemplate() *excelize.File {
	f := excelize.NewFile()
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	// 设置默认字体
	f.SetDefaultFont("宋体")

	// 设置提醒的字体类型
	style, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Color:  "#FF0000",
			Bold:   true,
			Family: "宋体",
		},
	})
	if err != nil {
		fmt.Println(err)
	}
	f.SetCellStyle("Sheet1", "A1", "A1", style)
	f.SetCellValue("Sheet1", "A1", "说明:")
	f.SetCellValue("Sheet1", "A2", "品牌名称，仅限中文、数字、英文，字数不超过12个汉字；")
	f.SetCellValue("Sheet1", "A3", "品牌描述，仅限中文、数字、英文，字数不超过240个汉字；")
	f.SetCellValue("Sheet1", "A4", "品牌铺号，仅限中文、数字、英文，字数不超过8个汉字；")
	f.SetCellValue("Sheet1", "A5", "联系电话，仅限数字、字符，字数不超过15个汉字；")
	f.SetCellValue("Sheet1", "A6", "品牌楼层，仅限数字、英文，必须和位置下的楼层信息一致；")
	f.SetCellValue("Sheet1", "A7", "注意：不要修改excel任何格式，文本信息必须清除格式，否则会导入失败。")
	f.SetCellStyle("Sheet1", "A7", "A7", style)
	f.SetCellValue("Sheet1", "A9", "品牌名称")
	f.SetCellValue("Sheet1", "B9", "品牌描述")
	f.SetCellValue("Sheet1", "C9", "品牌铺号")
	f.SetCellValue("Sheet1", "D9", "联系电话")
	f.SetCellValue("Sheet1", "E9", "品牌楼层")
	// 设置列宽
	f.SetColWidth("Sheet1", "A", "A", 20)
	f.SetColWidth("Sheet1", "B", "B", 50)
	f.SetColWidth("Sheet1", "C", "C", 20)
	f.SetColWidth("Sheet1", "D", "D", 20)
	f.SetColWidth("Sheet1", "E", "E", 20)
	return f
}

// ImportBrands 批量导入品牌
func (Brand) ImportBrands(locationID string, reader io.Reader) (successCount int, failedBrands []string, err error) {
	db := mysql.NewDB()
	failedBrands = []string{}
	// 判断位置是否存在
	var count int64
	db.Model(&models.Location{}).Where("id = ?", locationID).Count(&count)
	if count <= 0 {
		return 0, []string{}, errorx.New("位置不存在", -1)
	}

	xlsx, err := excelize.OpenReader(reader)
	if err != nil {
		return 0, []string{}, errorx.New("文件有误", -1)
	}
	rows, _ := xlsx.GetRows("Sheet1")
	if len(rows) < 10 {
		return 0, []string{}, errorx.New("品牌不能为空", -1)
	}
	rows = rows[9:]

	// 遍历每个品牌进行添加或更新
	for _, row := range rows {
		if len(row) < 5 {
			continue
		}
		var brandExists bool
		var brandID string
		// 添加品牌
		if row[0] == "" {
			continue
		}
		// 品牌新建或更新
		{
			var brand models.Brand
			rowsAffected := db.Model(&models.Brand{}).
				Where("name = ?", row[0]).
				Where("location_id = ?", locationID).
				Take(&brand).RowsAffected
			// 存在就更新
			if rowsAffected == 1 {
				if !lo.Contains(failedBrands, row[0]) {
					failedBrands = append(failedBrands, row[0])
				}
				brandExists = true
				brandID = brand.ID
				db.Model(&models.Brand{}).Where("id = ?", brand.ID).Update("desc", row[1])
			} else { // 不存在，新建
				var brand models.Brand
				brand.Name = row[0]
				brand.Desc = row[1]
				brand.LocationID = locationID
				rowsAffected := db.Model(&models.Brand{}).Create(&brand).RowsAffected
				if rowsAffected == 1 {
					successCount++
					brandExists = true
					brandID = brand.ID
				}
			}
		}

		// 如果品牌存在或添加成功，则更新其关联信息
		if brandExists {
			var floorExists bool
			// 查询楼层,不存在就创建
			var floor models.Floor
			rowsAffected := db.Model(&models.Floor{}).
				Where("name = ?", row[4]).
				Where("location_id = ?", locationID).
				Take(&floor).RowsAffected
			if rowsAffected == 1 {
				floorExists = true
			} else if rowsAffected == 0 {
				floor.Name = row[4]
				floor.LocationID = locationID
				rowsAffected := db.Model(&models.Floor{}).Create(&floor).RowsAffected
				if rowsAffected == 1 {
					floorExists = true
				}
			}
			// 存在或创建成功，则更新楼层品牌关联信息
			if floorExists {
				db.Where(models.FloorBrand{
					BrandID: brandID,
				}).Assign(models.FloorBrand{
					FloorID:      floor.ID,
					ContactPhone: row[3],
					ShopNO:       row[2],
				}).FirstOrCreate(&models.FloorBrand{})
			}
		}
	}
	return successCount, failedBrands, nil
}

// EditBrand 编辑品牌
func (Brand) EditBrand(brandID, name, logo, desc, floorID, contactPhone, shopNO string) error {
	db := mysql.NewDB()
	// 判断品牌是否存在
	var brandRecord models.Brand
	rowsAffected := db.Model(&models.Brand{}).Where("id = ?", brandID).Take(&brandRecord).RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("品牌不存在", -1)
	}

	// 删除旧的logo
	if logo != "" && filepath.Base(brandRecord.Logo) != filepath.Base(logo) {
		_, err := os.Stat(brandRecord.Logo)
		if err == nil {
			err := os.Remove(brandRecord.Logo)
			if err != nil {
				return errorx.New("旧logo删除失败", -1)
			}
		}
		// 从临时文件夹中移动地图导航文件
		saveDir := path.Join(config.Config.FileSaveDir, "brand")
		logo, err = file.SaveUploadFileTo(logo, saveDir)
		if err != nil {
			return err
		}
	}

	// 编辑品牌
	var brand models.Brand
	brand.Name = name
	brand.Logo = logo
	brand.Desc = desc
	rowsAffected = db.Model(&models.Brand{}).
		Where("id = ?", brandID).
		Updates(&brand).RowsAffected
	if rowsAffected <= 0 {
		errorx.New("编辑品牌失败", -1)
	}

	// 创建或更新关联
	if floorID != "" {
		var count int64
		db.Model(&models.Floor{}).Where("id = ?", floorID).Count(&count)
		if count <= 0 {
			return errorx.New("楼层不存在", -1)
		}
		db.Where(models.FloorBrand{
			BrandID: brandID,
		}).Assign(models.FloorBrand{
			FloorID:      floorID,
			ContactPhone: contactPhone,
			ShopNO:       shopNO,
		}).FirstOrCreate(&models.FloorBrand{})
	}

	return nil
}

// DeleteBrand 删除品牌
func (Brand) DeleteBrand(brandID string) error {
	db := mysql.NewDB()
	// 判断品牌是否存在
	var brandRecord models.Brand
	rowsAffected := db.Model(&models.Brand{}).
		Where("id = ?", brandID).
		Take(&brandRecord).RowsAffected
	if rowsAffected <= 0 {
		return errorx.New("品牌不存在", -1)
	}

	// 删除品牌logo
	_, err := os.Stat(brandRecord.Logo)
	if err == nil {
		err := os.Remove(brandRecord.Logo)
		if err != nil {
			return errorx.New("删除logo失败", -1)
		}
	}

	// 删除品牌
	{
		rowsAffected := db.Model(&models.Brand{}).
			Where("id = ?", brandID).
			Delete(&models.Brand{}).RowsAffected
		if rowsAffected <= 0 {
			errorx.New("删除品牌失败", -1)
		}
	}

	return nil
}
